var tgd = tgd || {};
tgd.Math = tgd.Math || {};

/*  http://en.wikipedia.org/wiki/Magic_square  */
/* http://en.wikipedia.org/wiki/Siamese_method */

tgd.Math.MagicSquare = function(n) {
    this._n = n;
    this._numCells = Math.pow(this._n, 2);
    this._data = [];

    for (var i = 0; i < this._n; ++i) {
        this._data[i] = [];

        for (var j = 0; j < this._n; ++j) {
            this._data[i][j] = 0;
        }
    }

	/* http://en.wikipedia.org/wiki/Siamese_method */
    if (this._n % 2 != 0) {  //odd
        /*
        Starting from the central column of the first row with the number 1,
        the fundamental movement for filling the squares is diagonally up
        and right, one step at a time. If a filled square is encountered,
        one moves vertically down one square instead, then continuing as
        before. When a move would leave the square, it is wrapped around
        to the last row or first column, respectively.

start r	start c	end r	end c
        0	0	2	1
        0	1	2	2
        0	2	2	0
        1	0	0	1
        1	1	0	2
        1	2	0	0
        2	0	1	1
        2	1	1	2
        2	2	1	0


        */

        var col = parseInt(this._n / 2, 10);
        var row = 0;

        for (var i = 1; i <= this._numCells; ++i) {
            this._data[row][col] = i;
            if (i == this._numCells) {
                break;
            }

            //todo: set next row/col.
            var found = false;
            while (!found) {
                var temprow = (row + this._n - 1) % this._n;
                var tempcol = (col + 1) % this._n;

                if (this._data[temprow][tempcol] == 0) {
                    found = true;
                } else {
                    temprow = (row + 1) % this._n;  //move down
                    tempcol = col;

                    if (this._data[temprow][tempcol] == 0) {
                        found = true;
                    }
                }

                row = temprow;
                col = tempcol;
            }
        }
    } else if (((this._n - 2) / 4).toString().indexOf(".") < 0) {  /* singly even -> http://en.wikipedia.org/wiki/Strachey_method_for_magic_squares */
		throw new Error("NOT SUPPORTED YET!  SINGLY EVEN WILL BE SUPPORTED SOON!");
    } else {
        throw new Error("ODD ONLY NOW SUPPORTED YET!");
    }

    if (typeof tgd.Math.MagicSquare._initialized == "undefined") {
        tgd.Math.MagicSquare.prototype.getN = function() {
            return this._n;
        }

        tgd.Math.MagicSquare.prototype.toString = function() {
            var str = "";
            for (var i = 0; i < this._n; ++i) {
                str += "(" + this._data[i].join(",") + "),";
            }
            return str.substr(0, str.length - 1) + ";";   /* remove trailing comma */
        }

        tgd.Math.MagicSquare._initialized = true;
    }
}